package engine.data;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;

import misc.Constant;
import misc.PersistenceTools;
import misc.Persistent;
import util.ArrayList;
import util.List;

/**
 * Tile class is an abstraction of a tile in the map.
 * 
 * @see Terrain
 * @see City
 * @see Unit
 * 
 * @author bigkif
 */
public final class Tile extends Persistent {

	public Terrain terrain;

	public List units;

	public City city;

	public Image image;

	private boolean changed = true;

	public static final byte IMAGE_WIDTH = 16;

	public static final byte IMAGE_HEIGHT = 16;

	public boolean[] isVisible;

	short[] unitRangeCount;

	public Tile(final byte playerCount) {
		isVisible = new boolean[playerCount];
		unitRangeCount = new short[playerCount];
	}

	public Tile(final short id, final byte playerCount, final byte terrainType) {
		this(playerCount);
		this.terrain = new Terrain(terrainType);
		this.setId(id);
		this.terrain.setId(id);
	}

	public Tile() {
		//
	}

	public boolean hasEnnemyUnits(final Player player) {
		if (this.units != null && this.units.size() > 0)
			return ((Unit) this.units.get(0)).player.civilization != player.civilization;
		return false;
	}

	public List getEnnemyUnits(final Player player) {
		if (this.hasEnnemyUnits(player))
			return this.units;
		return null;
	}

	public Unit getBestDefenseUnit() {
		if (this.units != null && this.units.size() > 0) {
			Unit bestUnit = (Unit) this.units.get(0);
			for (short index = 1; index < this.units.size(); index++) {
				if (UnitType.getDP(((Unit) this.units.get(index)).type) > UnitType.getDP(bestUnit.type))
					bestUnit = (Unit) this.units.get(index);
			}
			return bestUnit;
		}
		return null;
	}

	public void irrigate() {
		this.changed = true;
		this.terrain.irrigate();
	}

	public void mine() {
		this.changed = true;
		this.terrain.mine();
	}

	public void buildFortress() {
		this.changed = true;
		this.terrain.buildBortress();
	}

	public void setChanged() {
		this.changed = true;
	}

	public Image getImage(final Player player, final boolean removeEnnemyUnits) {
		this.changed = true;
		refreshImage(player, removeEnnemyUnits);
		return this.image;
	}

	public void revealTile(final Player player) {
		this.changed = true;
		refreshImage(player, false);
	}

	public void refreshImage(final Player player, final boolean removeEnnemyUnits) {
		isVisible[player.getId()] = true;
		//if (player.type == Player.HUMAN)
		if (player.showOnScr)
			if (this.image == null || this.changed || removeEnnemyUnits) {
				this.changed = false;
				this.image = Image.createImage(IMAGE_WIDTH, IMAGE_HEIGHT);
				Graphics graphicsImage = this.image.getGraphics();
				graphicsImage.drawImage(this.terrain.getImage(), 0, 0, Graphics.TOP | Graphics.LEFT);
				if (this.city != null)
					graphicsImage.drawImage(this.city.image, 0, 0, Graphics.TOP | Graphics.LEFT);
				if (this.units != null && this.units.size() > 0)
					if (!removeEnnemyUnits || !this.hasEnnemyUnits(player)
							|| (this.hasEnnemyUnits(player) && this.unitRangeCount[player.getId()] > 0)) {
						graphicsImage.drawImage(((Unit) this.units.get(0)).getImage(), 0, 0, Graphics.TOP
								| Graphics.LEFT);
					}
			}
	}

	public void addPeopleCity() {
		this.changed = true;
		final byte maxWOAqueduct = 10;
		if (this.city.getSize() <= maxWOAqueduct || this.city.hasBuilding(Building.AQUEDUCT))
			this.city.addPeople(People.CONTENT);
		if (this.city.hasBuilding(Building.GRANARY))
			this.city.foodStorageBox = (short) (this.city.getMaxFoodBox() / 2);
		this.city.refreshImage();
		this.city.chooseBestTiles(true);
	}

	void addUnit(final Unit unit) {
		if (units == null) {
			this.units = new ArrayList(Constant.INIT_TILE_UNITS_SIZE);
			this.changed = true;
		}
		this.units.add(0, unit);
	}

	void removeUnit(final Unit unit) {
		this.units.remove(unit);
		if (units.size() == 0) {
			this.changed = true;
			this.units = null;
		}
	}

	void addCity(final City newCity) {
		this.city = newCity;
		this.changed = true;
	}

	void removeCity() {
		this.city = null;
		this.changed = true;
	}

	void refreshUnitsLastSeenPosition(final Player player, final short x, final short y) {
		if (this.units != null) {
			for (int k = 0; k < this.units.size(); k++) {
				Unit unit = (Unit) this.units.get(k);
				unit.lastSeenPosition[player.getId()][0] = x;
				unit.lastSeenPosition[player.getId()][1] = y;
			}
		}
	}

	public String toString() {
		StringBuffer sb = new StringBuffer();
		sb.append("Tile[terrain='").append(terrain).append("', city='").append(city).append("', units='").append(units)
				.append("']");
		return sb.toString();
	}

	public void persist(final DataOutputStream dout, final boolean complete) throws IOException {
		if (complete) {
			PersistenceTools.persist(this.city, dout, false);
			PersistenceTools.persistBooleanArray(this.isVisible, dout);
			PersistenceTools.persist(this.terrain, dout, complete);
			PersistenceTools.persistShortArray(this.unitRangeCount, dout);
			PersistenceTools.persistList(this.units, dout, false);
		}
	}

	public void resurrect(final DataInputStream din, final boolean complete) throws IOException {
		if (complete) {
			this.changed = true;
			this.city = PersistenceTools.resurrectCity(din, false);
			this.isVisible = PersistenceTools.resurrectBooleanArray(din);
			this.terrain = PersistenceTools.resurrectTerrain(din, complete);
			this.unitRangeCount = PersistenceTools.resurrectShortArray(din);
			this.units = PersistenceTools.resurrectUnitList(din, false);
		}
	}

}
